package com.dkh.recommend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dkh.recommend.dto.MusicUploadDTO;
import com.dkh.recommend.dto.MusicUploadDTO2;
import com.dkh.recommend.dto.Result;
import com.dkh.recommend.dto.UserDTO;
import com.dkh.recommend.entity.TbLabel;
import com.dkh.recommend.entity.TbMusic;
import com.dkh.recommend.entity.TbMusicLabel;
import com.dkh.recommend.entity.TbRelate;
import com.dkh.recommend.mapper.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dkh.recommend.service.ITbLabelService;
import com.dkh.recommend.service.ITbMusicLabelService;
import com.dkh.recommend.service.ITbMusicService;
import com.dkh.recommend.utils.RecScoreUtils;
import com.dkh.recommend.utils.UserHolder;
import com.sun.org.apache.bcel.internal.generic.LineNumberGen;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.dkh.recommend.utils.RedisConstants.MUSIC_LIKE_KEY;
import static com.dkh.recommend.utils.RedisConstants.PLAY_LIST_KEY;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author dkh
 * @since 2022-12-14
 */
@Slf4j
@Service
@Transactional
public class TbMusicServiceImpl extends ServiceImpl<TbMusicMapper, TbMusic> implements ITbMusicService {

//    可能会产生循环依赖
    @Autowired
    private ITbMusicLabelService musicLabelService;

    @Autowired
    private ITbLabelService labelService;

    @Autowired
    private TbMusicMapper musicMapper;


    @Autowired
    private TbRelateMapper relateMapper;

    @Autowired
    private TbCommentMapper commentMapper;

    @Autowired
    private TbPlaylistMapper playlistMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private TbCollectMapper collectMapper;







    /**
     * 上传发布音乐
     * @param  musicUploadDTO
     * @return
     */
    @Override
    @Transactional
    public Result uploadmusic(MusicUploadDTO musicUploadDTO) {
//        tbmusic为空时返回错误信息
        if (StrUtil.hasBlank(musicUploadDTO.toString()) || musicUploadDTO.getMusicUrl().isEmpty() || musicUploadDTO.getMusicIcon().isEmpty() ){
        return Result.fail("音乐关键信息不全...发布失败");
        }
        TbMusic tbMusic = BeanUtil.toBean(musicUploadDTO, TbMusic.class);
        //        从locolThread中获取当前用户的名字
        Long userId = UserHolder.getUser().getUserId();
//        保存音乐上传者id
        tbMusic.setMusicUploaderId(userId);
        boolean b = save(tbMusic);

//        获取当前音乐的id
        Long musicId = tbMusic.getMusicId();
//        labelmusicList
        List<TbMusicLabel> musicLabelList = new ArrayList<>();
//        标签列表
        List<String> labelList = musicUploadDTO.getLabelList();

//        获取musiclbelList 放入map方便根据label名字获取id
        List<TbLabel> tbLabelList = labelService.list();
        Map<String,Long> labelMap = new HashMap<>();
        tbLabelList.stream().forEach(tbLabel -> {
            labelMap.put(tbLabel.getLabelName(),tbLabel.getLabelId());
        });

        labelList.stream().forEach(label->{
//            获取写入音乐id
            TbMusicLabel musicLabel = new TbMusicLabel();
            musicLabel.setMusicId(musicId);
            Long labelId = labelMap.get(label);
            musicLabel.setLabelId(labelId);
//            musicLabel.setLabelId(Long.valueOf(label));
            musicLabelList.add(musicLabel);
        });
//        保存音乐标签
        boolean saveLabel = musicLabelService.saveBatch(musicLabelList);
        if (!saveLabel){
            return Result.fail("发布失败");
        }

        return Result.ok();
    }
    @Override
    public Result uploadmusic2(MusicUploadDTO2 musicUploadDTO2) {
        Long userId = UserHolder.getUser().getUserId();

        //        tbmusic为空时返回错误信息
        if (StrUtil.hasBlank(musicUploadDTO2.toString())){
            return Result.fail("音乐关键信息不全...发布失败");
        }
        TbMusic tbMusic = BeanUtil.toBean(musicUploadDTO2, TbMusic.class);
        //        从locolThread中获取当前用户的名字
//        Long userId = UserHolder.getUser().getUserId();

//        保存音乐上传者id
        tbMusic.setMusicUploaderId(userId);
        boolean b = save(tbMusic);

//        获取当前音乐的id
        Long musicId = tbMusic.getMusicId();
//        labelmusicList
        List<TbMusicLabel> musicLabelList = new ArrayList<>();
//        标签
            musicUploadDTO2.getLabel2();

//            获取写入音乐id
            TbMusicLabel musicLabel = new TbMusicLabel();
            musicLabel.setMusicId(musicId);
//           查找lableid
            LambdaQueryWrapper<TbLabel> wrapper = new LambdaQueryWrapper<>();
             wrapper.eq(TbLabel::getLabelName,musicUploadDTO2.getLabel2());
             TbLabel label = labelService.getOne(wrapper);
             musicLabel.setLabelId(label.getLabelId());
            musicLabelList.add(musicLabel);

//        保存音乐标签
        boolean saveLabel = musicLabelService.saveBatch(musicLabelList);
        if (!saveLabel){
            return Result.fail("发布失败");
        }

        return Result.ok();
    }


//    将音乐加入音乐收藏夹
//    todo  将音乐加入音乐收藏夹
    @Override
    public Result put2Collect(String musicId, String collectId) {

        return null;
    }

//    根据音乐id获取详细信息
    @Override
    public Result getAllInfo(String musicId) {

        Long Id = Long.valueOf(musicId);
        TbMusic tbMusic = this.getById(Id);

//        添加是否已经点赞进去Tbmusic
        isMsicuLiked(tbMusic);
        return Result.ok(tbMusic);
    }

    /**
     * 根据音乐Id删除我的音乐
     * @param musicId
     * @return
     */
    @Override
    @Transactional
    public Result deleteMyMusic(String musicId) {
//        获取当前用户Id
        Long userId = UserHolder.getUser().getUserId();
//        转换为Long
        Long musicIdL = Long.valueOf(musicId);

//        条件wrapper： userId，musicId相等的条件
        LambdaQueryWrapper<TbMusic> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TbMusic::getMusicUploaderId,userId)
                .eq(TbMusic::getMusicId,musicIdL);
        boolean rm = this.remove(wrapper);
        LambdaQueryWrapper<TbMusicLabel> mlwrapper = new LambdaQueryWrapper<>();
        mlwrapper.eq(TbMusicLabel::getMusicId,musicIdL);

        boolean rm2 = musicLabelService.remove(mlwrapper);
        if (!rm || !rm2 ){
            return Result.fail("删除失败");
        }
//        删除音乐id有关的关系表
        relateMapper.deleteByMusicId(musicIdL);

        commentMapper.deleteByMusicId(musicIdL);

        playlistMapper.deleteByMusicId(musicIdL);

        collectMapper.deleteByMusicId(musicIdL);


//        //        redis缓存的key
//        String key = PLAY_LIST_KEY+userId;
////        将redis缓存删除,保持数据统一
//        stringRedisTemplate.delete(key);

        return Result.ok();
    }

    /**
     * 根据标签id查找音乐列表
     * @param labelId
     * @return
     */
    @Override
    public Result selectMusicByLabelId(String labelId) {
        Long labelIdL = Long.valueOf(labelId);
        List<TbMusic> tbMusicList = musicMapper.selectByLabelId(labelIdL);
        return Result.ok(tbMusicList);
    }



    /**
     * 喜欢点赞音乐
     * 由于音乐点赞不是特别重要的数据，所以使用redis直接保存
     * @param musicId
     * @return
     */
    @Override
    @Transactional
    public Result likeMusic(String musicId) {
//        1.获取用户Id
        Long userId = UserHolder.getUser().getUserId();
        Long musicIdL = Long.valueOf(musicId);
        String msg = "操作成功";
        if (UserHolder.getUser().toString().isEmpty()||UserHolder.getUser().toString().equals("")){
//            用户未登陆请先登陆
            return Result.fail("请先登陆");
        }
//        //        2.判断当前登录用户是否已经点赞
        String key = MUSIC_LIKE_KEY + musicId;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
        if (score == null){
            // 3.如果未点赞，可以点赞
            // 3.1.数据库点赞数 + 1
//            boolean isSucess = this.update().setSql("music_like = music_like + 1").eq("music_like", musicIdL).update();

            Boolean isSucess = musicMapper.addCountLike(musicIdL);

            // 3.2.保存用户到Redis的set集合  zadd key value score
            if (isSucess){
                stringRedisTemplate.opsForZSet().add(key,userId.toString(),System.currentTimeMillis());
                msg = "点赞成功";
            }else {
                return Result.fail("点赞失败");
            }
//            点赞+1分
            TbRelate relate = new TbRelate();
            relate.setMusicId(musicIdL);
            relate.setUserId(userId);
            relate.setIndex(1);
            RecScoreUtils.addScore(relate,relateMapper);
        }else {
            // 4.如果已点赞，取消点赞
            // 4.1.数据库点赞数 -1
            boolean isSucess2 = this.update().setSql("music_like = music_like - 1").eq("music_like", musicIdL).update();
            // 4.2.把用户从Redis的set集合移除
            stringRedisTemplate.opsForZSet().remove(key,userId.toString());
            msg = "取消点赞成功";
//            取消点赞 -1
            TbRelate relate = new TbRelate();
            relate.setMusicId(musicIdL);
            relate.setUserId(userId);
            relate.setIndex(1);
            RecScoreUtils.decScore(relate,relateMapper);
        }


        return Result.ok(msg);

    }

    @Override
    public Result orNotLikeMusic(String musicId) {

//        获取当前登陆的用户
        UserDTO user = UserHolder.getUser();
        Long userId = user.getUserId();

        if (user == null) {
            // 用户未登录，无需查询是否点赞
            return null;
        }

        //        2.判断当前登录用户是否已经点赞
        String key = MUSIC_LIKE_KEY + musicId;
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());

        return Result.ok(score != null);
    }

    /*
    获取热点音乐
     */
    @Override
    public Result GetHotMusic() {
       List<TbMusic> musicList = musicMapper.GetHotMusic();
        return Result.ok(musicList);
    }



    //    用于判断是否点赞
    private void isMsicuLiked(TbMusic music) {

        //        获取当前登陆的用户
        UserDTO user = UserHolder.getUser();
        Long userId = user.getUserId();

        if (user == null) {
            // 用户未登录，无需查询是否点赞
            return ;
        }

        //        2.判断当前登录用户是否已经点赞
        String key = MUSIC_LIKE_KEY + music.getMusicId();
        Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString());
       music.setIsLike( score != null);

    }


    /**
     * 根据音乐标签查找音乐
     * @param label_id
     * @return
     */
    @Override
    public Result getmusicbylabel(Long label_id) {
//        从音乐标签关系表中查找该标签的音乐id
        LambdaQueryWrapper<TbMusicLabel> musicIdQuerryWrapper = new LambdaQueryWrapper<>() ;
        musicIdQuerryWrapper.eq(TbMusicLabel::getLabelId,label_id);
//
        List<TbMusicLabel> musicLabelList = musicLabelService.list(musicIdQuerryWrapper);

//        将查询到的音乐id取出放入音乐musicidlist
        List<Long> musicidlist = new ArrayList<>();
        musicLabelList.stream().forEach(musicLabel->{
        musicidlist.add(musicLabel.getMusicId());
        });

//        根据音乐id查找该音乐信息
        List<TbMusic> musicByLabelList = listByIds(musicidlist);
//        返回该列表
        return Result.ok(musicByLabelList);
// todo 将内容缓存到redis

//        List<MusicUploadDTO> musicUploadDTOList = new ArrayList<>();
//        将该音乐信息list存入dtolist
//        musicByLabelList.stream().forEach(musicByLabel->{
//            MusicUploadDTO musicUploadDTO = new MusicUploadDTO();
////            将tbmusic转成musicDto实体
//            BeanUtil.toBean(musicByLabel, MusicUploadDTO.class);
////            为每个musicDTO添加labelList
//            List<TbLabel> labelList = new ArrayList<>();
////            根据labelid
//
//            musicUploadDTO.setLabelList(labelList);
//            musicUploadDTOList.add();
//        });

    }


//    分页查看所有音乐
    @Override
    public Result musiclist(int pageNumber, int pageSize) {

//        第几页，页面大小,执行分页查询后会将数据返回给page
        IPage<TbMusic> musicPage= new Page<>(pageNumber,pageSize);

        LambdaQueryWrapper<TbMusic> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(TbMusic::getMusicLike)
                .orderByDesc(TbMusic::getMusicId);
        this.page(musicPage,wrapper);
//         获取分页中的内容
        List<TbMusic> records = musicPage.getRecords();
        return Result.ok(musicPage);

    }

//    根据条件查找音乐
    @Override
    public Result selectmusic(String condition) {

        LambdaQueryWrapper<TbMusic> queryWrapper = new LambdaQueryWrapper<>();
//        根据歌名查 或 根据歌手查  根据歌曲的点赞量，收藏量，评论量倒序排序
        queryWrapper.like(TbMusic::getMusicName,condition)
                .or()
                .like(TbMusic::getMusicAuthor,condition)
                .orderByDesc(TbMusic::getMusicLike,TbMusic::getCountCollect,TbMusic::getCountComment);

        List<TbMusic> musicList = list(queryWrapper);
        return Result.ok(musicList);
    }

    /**
     * 查找本人上传的音乐
     * @return
     */
    @Override
    public Result getmymusic() {
        Long userId = UserHolder.getUser().getUserId();
        LambdaQueryWrapper<TbMusic> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TbMusic::getMusicUploaderId,userId).orderByDesc(TbMusic::getMusicId);
        List<TbMusic> musicList = list(queryWrapper);
        return Result.ok(musicList);
    }




}
